
-- with Ada.Numerics.Real_Arrays;  
-- use Ada.Numerics.Real_Arrays;

with Ada.Text_IO; use Ada.Text_IO; 

-- https://leetcode.com/problems/spiral-matrix/
procedure leet57_spiralmatrix is
    type vector is array (positive range<>) of integer;
    -- wondering why real_matrices can't be used with integers..
    type matrix is array (positive range <>, positive range <>) of integer;

--    procedure print(m : in matrix) is
    procedure print(v : in vector) is
    begin 
--        for i of m loop -- iterates through entire matrix
--        for i in m'range(1) loop -- counts number of rows
--        for i in m'range(2) loop -- counts number of columns
        for element of v loop
            put(element'image & " ");
        end loop;
    end print;

    function spiralorder(m : in matrix) return vector is
        -- direction to append elements to vector
        horiz : boolean := true;
        posi  : boolean := true;
        length : positive := m'length(1) * m'length(2);
        output : vector (1 .. length) := (others => -1);
        x : positive := 1; -- current row
        y : positive := 1; -- current column
        r_offset : integer := 0; -- right boundary
        l_offset : integer := 1; -- left boundary
        t_offset : integer := 1; -- top boundary
        b_offset : integer := 0; -- bottom boundary
    begin
        for i in positive range 1 .. length loop
            output(i) := m(x,y);
--            put_line(m(x,y)'image);
            if horiz and posi then -- go right
                y := y + 1;
                if y = (m'length(2) + b_offset) then -- hit the end
                    horiz := not horiz; -- go vertical
                    -- went right, therefore, top row is off-limits
                    t_offset := t_offset + 1;
                end if;
            elsif not horiz and posi then -- go down
                x := x + 1;
                if x = (m'length(1) + b_offset) then
                    horiz := not horiz;
                    posi := not posi;
                    -- went down; therefore right column is off limits
                    r_offset := r_offset - 1;
                end if;
            elsif horiz and not posi then -- go left
                y := y - 1;
                if y = l_offset then
                    horiz := not horiz;
                    b_offset := b_offset - 1;
                end if;
            elsif not horiz and not posi then -- go up
                x := x - 1;
                if x = t_offset then
                    horiz := not horiz;
                    l_offset := l_offset + 1;
                    posi := not posi;
                end if;
            end if;
        end loop;
        return output;
    end spiralorder;

    procedure main is
        t1 : matrix := ((1,2,3),
                        (4,5,6),
                        (7,8,9)
                       );
        v1 : vector := spiralorder(t1);
        t2 : matrix := ((1,2,3,4),
                        (5,6,7,8),
                        (9,10,11,12)
                       );
        v2 : vector := spiralorder(t2);
        t3 : matrix := ((1, 2,  3,  4,  5,  6,   7),
                        (8, 9,  10, 11, 12, 13, 14),
                        (15,16, 17, 18, 19, 20, 21),
                        (22,23, 24, 25, 26, 27, 28)
                       );
        v3 : vector := spiralorder(t3);
    begin
        print(v1);
        new_line;
        print(v2);
        new_line;
        print(v3);
    end main;
begin
    put_line("This is leetcode algorithm challenge #57 - Spiral Matrix");
    main;
end leet57_spiralmatrix;
